package com.sf.iisp.bind.helper;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

import com.sf.novatar.base.dao.CommonDao;
import com.sf.novatar.base.domain.RequestParams;

public class DetachedCriteriaGenerator {
    /**
     * 根据class类型及queryParam生成查询条件
     *
     * @param queryParam
     * @param clazz
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static DetachedCriteria generateCriteria(RequestParams queryParam, Class clazz) {
        DetachedCriteria criteria = DetachedCriteria
                .forClass(clazz);
        try {
            generateCriteriaByTagAndFieldName(queryParam, criteria, clazz);
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
        return criteria;
    }


    /**
     * 根据class类型及queryParam生成查询条件并返回唯一结果
     *
     * @param queryParams
     * @param clazz
     * @param dao
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Object findUniqueResult(RequestParams queryParams, Class clazz, CommonDao dao) {
        DetachedCriteria criteria = DetachedCriteriaGenerator.generateCriteria(queryParams, clazz);
        return criteria.getExecutableCriteria(dao.getCurrentSession()).uniqueResult();
    }

    /**
     * 根据class类型及map生成查询条件并返回唯一结果
     *
     * @param paramMap
     * @param clazz
     * @param dao
     * @param notSupportLike
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Object findUniqueResult(Map<String, String> paramMap, Class clazz, CommonDao dao, boolean notSupportLike) {
        return findUniqueResult(createRequestParams(paramMap, notSupportLike), clazz, dao);
    }

    /**
     * 根据class类型及queryParam生成查询条件并返回结果集
     *
     * @param queryParams
     * @param clazz
     * @param dao
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static List findResults(RequestParams queryParams, Class clazz, CommonDao dao) {
        DetachedCriteria criteria = DetachedCriteriaGenerator.generateCriteria(queryParams, clazz);
        return criteria.getExecutableCriteria(dao.getCurrentSession()).list();
    }

    /**
     * 根据class类型及map生成查询条件并返回结果集
     *
     * @param paramMap
     * @param clazz
     * @param dao
     * @param notSupportLike 是否支持模糊查找，不支持为true
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static List findResults(Map<String, String> paramMap, Class clazz, CommonDao dao, boolean notSupportLike) {
        return findResults(createRequestParams(paramMap, notSupportLike), clazz, dao);
    }

    /**
     * 根据类中字段名称及是否支持模糊查找
     *
     * @param isNotSupportLikeSearching
     * @param fieldName
     * @param queryParam
     * @param criteria
     */
    @SuppressWarnings("rawtypes")
    private static void generateCriteriaByTagAndFieldName(RequestParams queryParam,
                                                          DetachedCriteria criteria, Class clazz) {
        Field[] fs = findAllField(clazz);
        for (Field f : fs) {
            //根据字段生成查询条件
            generateCriteriaByTag(f, queryParam, criteria);
        }
        //根据SQL附加查询条件
        if (StringUtils.isNotEmpty(queryParam.getQueryValue("sql"))) {
            criteria.add(Restrictions.sqlRestriction(queryParam.getQueryValue("sql")));
        }

    }

    /**
     * 根据是否支持模糊查找生成查询条件
     *
     * @param isNotSupportLikeSearching
     */
    private static void generateCriteriaByTag(Field field, RequestParams queryParam,
                                              DetachedCriteria criteria) {
        //Y:不支持模糊查找。否则支持模糊查找
        boolean isNotSupportLikeSearching = "Y".equals(queryParam.getQueryValue("notSupportLike"));
        String fieldName = field.getName();
        String queryValue = queryParam.getQueryValue(fieldName);
        if (StringUtils.isNotEmpty(queryValue)) {
            Object paramValue = queryValue;
            if (field.getType().getName().contains("Long")) {
                paramValue = Long.valueOf(queryValue);
            } else if (field.getType().getName().contains("Integer")) {
                paramValue = Integer.valueOf(queryValue);
            }

            if (!String.class.isInstance(paramValue) || isNotSupportLikeSearching) {
                criteria.add(Restrictions.eq(fieldName, paramValue));
            } else {
                //模糊查找时，对于需要精确查找的个别字段进行处理，字段需要以:fieldName:的形式
                String useeq = queryParam.getQueryValue("useeq");
                if (StringUtils.isNotEmpty(useeq) && useeq.indexOf(":" + fieldName + ":") >= 0) {
                    criteria.add(Restrictions.eq(fieldName, paramValue));
                } else {
                    criteria.add(Restrictions.like(fieldName, queryValue, MatchMode.ANYWHERE));
                }
            }
        }
    }

    /**
     * 获取类中所有字段
     *
     * @return
     */
    @SuppressWarnings("rawtypes")
    private static Field[] findAllField(Class clazz) {
        Field[] fields = clazz.getDeclaredFields();
        return fields;
    }


    /**
     * 根据查询条件创建请求参数对象
     *
     * @param paramMap
     * @param notSupportLike
     * @return
     */
    private static RequestParams createRequestParams(Map<String, String> paramMap, boolean notSupportLike) {
        RequestParams queryParams = new RequestParams(paramMap);
        if (notSupportLike) {
            queryParams.setQueryValue("notSupportLike", "Y");
        }
        return queryParams;
    }

}
